import React from 'react'
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import classNames from 'classnames';
import { LocaleProvider, Drawer, Button, Icon } from 'antd';
import zh_CN from 'antd/lib/locale-provider/zh_CN'
import Dialog, { destroyFns } from './Dialog';
import Spin from '@/components/Spin'
import ActionButton from 'antd/es/modal/ActionButton';
import request from '@/utils/request';
import settings from '@/settings'

const IS_REACT_16 = !!ReactDOM.createPortal;
const prefixDialogCls = 'x-dialog'

// 弹窗 脱离（独立的）虚拟dom结构，需要provider 原始 redux的store（包括ant的国际化组件）
// 新版 umi 拆除了 g_app ，升级的时候再考虑新的方式
const getStore = () => {
  return window.g_app._store
}

const noop =() => {}

export const ConfirmDialog = props => {
  const {
    prefixCls = prefixDialogCls,
    width = 416,
    type,
    title,
    content,
    className,
    style = {},
    mask = true,
    onCancel,
    onOk,
    okCancel = true,
    maskClosable = false,
    close,
    zIndex,
    afterClose,
    visible,
    keyboard,
    centered = true,
    getContainer,
    okType = 'primary',
    okText = '确定',
    cancelText = '取消',
    maskStyle,
    okButtonProps,
    cancelButtonProps,
    icon,
    iconType = 'question-circle',
    autoFocusButton,
    transitionName = 'zoom',
    maskTransitionName = 'fade'
  } = props;

  let _icon = icon || iconType;
  const contentPrefixCls = `${prefixCls}-confirm`;
  let _autoFocusButton = autoFocusButton == null ? false : autoFocusButton || 'ok';

  const classString = classNames(
    contentPrefixCls,
    `${contentPrefixCls}-${type}`,
    className,
  );

  const cancelButton = okCancel && (
    <ActionButton
        actionFn={onCancel}
        closeModal={close}
        autoFocus={_autoFocusButton === 'cancel'}
        buttonProps={cancelButtonProps}
      >
      {cancelText}
    </ActionButton>
  );

  const iconNode = typeof _icon === 'string' ? <Icon type={_icon} /> : _icon;

  return (
    <Dialog
      prefixCls={prefixCls}
      className={classString}
      wrapClassName={classNames({ [`${contentPrefixCls}-centered`]: !!centered })}
      onCancel={close.bind(this, { triggerCancel: true })}
      visible={visible}
      title=""
      transitionName={transitionName}
      footer=""
      maskTransitionName={maskTransitionName}
      mask={mask}
      maskClosable={maskClosable}
      maskStyle={maskStyle}
      style={style}
      width={width}
      zIndex={zIndex}
      afterClose={afterClose}
      keyboard={keyboard}
      centered={centered}
      getContainer={getContainer}
    >
      <div className={`${contentPrefixCls}-body-wrapper`}>
        <div className={`${contentPrefixCls}-body`}>
          {iconNode}
          <span className={`${contentPrefixCls}-title`}>{title}</span>
          <div className={`${contentPrefixCls}-content`}>{content}</div>
        </div>
        <div className={`${contentPrefixCls}-btns`}>
          {cancelButton}
          <ActionButton
              type={okType}
              actionFn={onOk}
              closeModal={close}
              autoFocus={autoFocusButton === 'ok'}
              buttonProps={okButtonProps}
            >
            {okText}
          </ActionButton>
        </div>
      </div>
    </Dialog>
  );
};
class WrapFrom extends React.Component {
  shouldComponentUpdate(nextProps) {
    return !!nextProps.visible;
  }
  render() {
    return (
      <React.Fragment>
        {this.props.children}
      </React.Fragment>
    )
  }
}
export class ModalDialog extends React.Component {
  state = {
    postLoading: false
  };
  // destroyOnClose为true会导致子集获取不到更新的props
  static defaultProps = {
    centered: true,
    // destroyOnClose: true,
    maskClosable: false,
    fixed: false,
    loading: false
  };
  // handleSubmit = () => {
  //   const {
  //     close
  //   } = this.props

  //   close()
  // };
  onCancel = (e) => {
    const {
      close,
      onCancel
    } = this.props;
    close.bind(this, {
      triggerCancel: true
    })()

    if (onCancel) {
      onCancel(e);
    }
  };
  onSubmit = close => {
    const {
      url,
      options = {},
      data,
      onOk
    } = this.props

    // let _close = close || noop

    // if (this.component) {
    //   const {
    //     handleSubmit
    //   } = this.component

    //   if (handleSubmit) {
    //     handleSubmit(_close, onOk ? ((...args) => {
    //       onOk(_close, ...args)
    //     }) : noop)
    //     return
    //   }
    // }
    // onOk && onOk(_close)
    
    let _onSubmit = onOk
    
    if (url) {
      _onSubmit = ({ reject, resolve }, params) => {
        if (params) {
          this.setState({
            postLoading: true
          })
          const {
            type = 'post',
            method,
            ...rest
          } = options

          request[type](url, {
            ...rest,
            data: {
              ...data,
              ...params
            }
          }).then(({code, data}) => {
            if (code === settings.code) {
              resolve(data)
              onOk && onOk(data)
            } else {
              reject(data)
            }
          })
        }
      }
    }

    return new Promise((resolve, reject) => {
      if (this.component) {
        const {
          handleSubmit
        } = this.component

        if (handleSubmit) {
          if (!_onSubmit) {
            this.setState({
              postLoading: true
            })
          }
          handleSubmit({ reject, resolve }, _onSubmit ? ((...args) => {
            if (!url) {
              this.setState({
                postLoading: true
              })
            }
            _onSubmit({ reject, resolve }, ...args)
          }) : noop)
          return
        }
      }
      if (!url && _onSubmit) {
        this.setState({
          postLoading: true
        })
        _onSubmit({ reject, resolve })
      } else {
        resolve()
      }
    }).then(
      (...args) => {

      },
      e => {
        this.setState({
          postLoading: false
        })
      }
    )
  };
  renderFooter = () => {
    const {
      postLoading
    } = this.state
    const {
      loading,
      close,
      showCancel = true,
      cancelText = '关闭',
      okType = 'primary',
      okText = '提交',
      // onOk,
      cancelButtonProps,
      okButtonProps
    } = this.props

    const _okButtonProps = {
      loading: postLoading,
      ...okButtonProps,
      disabled: loading
    }
    return (
      <React.Fragment>
        { 
          showCancel && <Button onClick={this.onCancel} {...cancelButtonProps}>
            {cancelText}
          </Button>
        }
        <ActionButton
            type={okType}
            actionFn={this.onSubmit}
            closeModal={close}
            autoFocus={true}
            buttonProps={_okButtonProps}
          >
          {okText}
        </ActionButton>
      </React.Fragment>
    )
  };
  saveComponent = node => {
    this.component = node
  };
  render() {
    const {
      url,
      options,
      data,
      component,
      close,
      visible,
      fixed,
      wrapClassName,
      afterClose,
      showCancel,
      loading,
      ...restProps
    } = this.props

    const dataLoading = {
      spinning: loading
    }
    const Component = component
    return (
      <Dialog
       {...restProps} 
       prefixCls={prefixDialogCls}
       wrapClassName={classNames({ [`${prefixDialogCls}-fixed`]: !!fixed }, wrapClassName)}
       visible={visible}
       // onOk={this.handleSubmit}
       onCancel={this.onCancel}
       footer={this.renderFooter()}
       afterClose={afterClose}
       forceRender={false}
       destroyOnClose={false}
       >
        <WrapFrom visible={visible}>
          <Spin
              {...dataLoading}
            >
            <Component loading={loading} data={data} getInstance={this.saveComponent} />
          </Spin>
        </WrapFrom>
      </Dialog>
    )
  }
}

export default function modal(Component, config) {
  const div = document.createElement('div');
  document.body.appendChild(div);
  let currentConfig = { ...config, close, visible: true };

  function close(...args) {
    currentConfig = {
      ...currentConfig,
      visible: false,
      afterClose: destroy.bind(this, ...args),
    };
    if (IS_REACT_16) {
      render(currentConfig);
    } else {
      destroy(...args);
    }
  }

  function update(newConfig) {
    currentConfig = {
      ...currentConfig,
      ...newConfig,
    };
    render(currentConfig);
  }

  function destroy(...args) {
    const unmountResult = ReactDOM.unmountComponentAtNode(div);
    if (unmountResult && div.parentNode) {
      div.parentNode.removeChild(div);
    }
    const triggerCancel = args.some(param => param && param.triggerCancel);
    if (config.onCancel && triggerCancel) {
      config.onCancel(...args);
    }
    for (let i = 0; i < destroyFns.length; i++) {
      const fn = destroyFns[i];
      if (fn === close) {
        destroyFns.splice(i, 1);
        break;
      }
    }
  }

  const store = getStore()

  function render(props) {
    ReactDOM.render(
      <LocaleProvider locale={zh_CN}>
        <Provider store={store}><Component {...props} /></Provider>
      </LocaleProvider>, div);
  }

  render(currentConfig);

  destroyFns.push(close);

  return {
    destroy: close,
    update,
  };
}

const prefixDrawerCls = 'x-drawer'

export class DrawerDialog extends React.Component {
  state = {
    postLoading: false
  };
  static defaultProps = {
    okType: 'primary',
    destroyOnClose: true,
    loading: false
  };
  onCancel = (e) => {
    const {
      onClose,
      onCancel
    } = this.props;
    onClose.bind(this, {
      triggerCancel: true
    })()

    if (onCancel) {
      onCancel(e);
    }
  };
  onSubmit = close => {
    const {
      url,
      options = {},
      data,
      onOk
    } = this.props
    
    let _onSubmit = onOk
    
    if (url) {
      _onSubmit = ({ reject, resolve }, params) => {
        if (params) {
          this.setState({
            postLoading: true
          })
          const {
            type = 'post',
            method,
            ...rest
          } = options

          request[type](url, {
            ...rest,
            data: {
              ...data,
              ...params
            }
          }).then(({code, data}) => {
            if (code === settings.code) {
              resolve(data)
              onOk && onOk(data)
            } else {
              reject(data)
            }
          })
        }
      }
    }

    return new Promise((resolve, reject) => {
      if (this.component) {
        const {
          handleSubmit
        } = this.component

        if (handleSubmit) {
          if (!_onSubmit) {
            this.setState({
              postLoading: true
            })
          }
          handleSubmit({ reject, resolve }, _onSubmit ? ((...args) => {
            if (!url) {
              this.setState({
                postLoading: true
              })
            }
            _onSubmit({ reject, resolve }, ...args)
          }) : noop)
          return
        }
      }
      if (!url && _onSubmit) {
        this.setState({
          postLoading: true
        })
        _onSubmit({ reject, resolve })
      } else {
        resolve()
      }
    }).then(
      (...args) => {

      },
      e => {
        this.setState({
          postLoading: false
        })
      }
    )
  };
  renderFooter = () => {
    const {
      postLoading
    } = this.state
    const {
      loading,
      onClose,
      showCancel = true,
      okText = '提交',
      okType = 'primary',
      // onOk,
      okButtonProps,
      cancelText = '取消',
      cancelButtonProps
    } = this.props;

    const _okButtonProps = {
      loading: postLoading,
      ...okButtonProps,
      disabled: loading
    }
    return (
      <div className={`${prefixDrawerCls}-footer`}>
        { 
          showCancel && <Button onClick={this.onCancel} {...cancelButtonProps}>
            {cancelText}
          </Button>
        }
        <ActionButton
            type={okType}
            actionFn={this.onSubmit}
            closeModal={onClose}
            autoFocus={true}
            buttonProps={_okButtonProps}
          >
          {okText}
        </ActionButton>
      </div>
    );
  };
  saveComponent = node => {
    this.component = node
  };
  render() {
    const defaultFooter = this.renderFooter()
    const {
      url,
      options,
      data,
      component,
      onClose,
      visible,
      footer,
      loading,
      showCancel,
      ...restProps
    } = this.props

    const dataLoading = {
      spinning: loading
    }
    const Component = component
    return (
      <Drawer
        {...restProps} 
        prefixCls={prefixDrawerCls}
        visible={visible}
        onClose={this.onCancel}
        >
        <WrapFrom visible={visible}>
          <Spin
            {...dataLoading}
            >
            <Component loading={loading} getInstance={this.saveComponent} data={data} />
            {footer === undefined ? defaultFooter : footer}
          </Spin>
        </WrapFrom>
      </Drawer>
    )
  }
}

export const drawer = (Component, config) => {
  const div = document.createElement('div');
  document.body.appendChild(div);

  let currentConfig = { ...config,
    onClose,
    visible: false,
    afterVisibleChange: visible => !visible && destroy()
  }

  function onClose(...args) {
    currentConfig = {
      ...currentConfig,
      visible: false,
    };
    if (IS_REACT_16) {
      render(currentConfig);
    } else {
      destroy(...args);
    }
  }

  function destroy(...args) {
    const unmountResult = ReactDOM.unmountComponentAtNode(div);
    if (unmountResult && div.parentNode) {
      div.parentNode.removeChild(div);
    }
    const triggerCancel = args.some(param => param && param.triggerCancel);
    if (config.onCancel && triggerCancel) {
      config.onCancel(...args);
    }
  }
  
  const store = getStore()

  function render(props) {
    ReactDOM.render(
      <LocaleProvider locale={zh_CN}>
        <Provider store={store}><Component {...props} /></Provider>
      </LocaleProvider>, div);
  }

  function update(newConfig) {
    currentConfig = {
      ...currentConfig,
      ...newConfig,
    };
    render(currentConfig);
  }

  render(currentConfig);

  return {
    destroy: onClose,
    update,
  }
}